// eee.Sheffield.PZ.Imaging
//
// Copyright ?Ping Zou, 2007
// sg71.cherub@gmail.com

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using eee.Sheffield.PZ.Math;

namespace eee.Sheffield.PZ.Imaging
{
    /// <summary>
    /// save tracking result
    /// </summary>
    public class LiuSunTrackResult
    {
        #region Fields
        private int _count = 0;
        private double _meanr = 0;

        private PZPoint _startCentrePoint = new PZPoint();
        private PZDirection _startVesselDirection = new PZDirection();
        private PZPoint _endCentrePoint = new PZPoint();
        private PZDirection _endVesselDirection = new PZDirection();

        private List<PZPoint> _cpArray = new List<PZPoint>();
        private List<PZDirection> _vdArray = new List<PZDirection>();
        private List<PZPoint> _ep1Array = new List<PZPoint>();
        private List<PZPoint> _ep2Array = new List<PZPoint>();
        private List<double> _rArray = new List<double>();
        private List<double> _signalLevelArray = new List<double>();
        private List<double> _backgroundLevelArray = new List<double>();

        //private string _exitMsg; 
        #endregion

        #region Properties
        public int Count { get { return _count; } }
        public double MeanRadius { get { return _meanr; } }
        public PZPoint StartCentrePoint { get { return _startCentrePoint; } }
        public PZPoint EndCentrePoint { get { return _endCentrePoint; } }
        public PZDirection StartVesselDirection { get { return _startVesselDirection; } }
        public PZDirection EndVesselDirection { get { return _endVesselDirection; } }

        public List<PZPoint> CentrePointArray { get { return _cpArray; } }
        public List<PZDirection> VesselDirectionArray { get { return _vdArray; } }
        public List<PZPoint> EdgePoint1Array { get { return _ep1Array; } }
        public List<PZPoint> EdgePoint2Array { get { return _ep2Array; } }
        public List<double> RadiusArray { get { return _rArray; } }
        public List<double> SignalLevelArray { get { return _signalLevelArray; } }
        public List<double> BackgroundLevelArray { get { return _backgroundLevelArray; } }
        //public string ExitMsg { get { return _exitMsg; } }
        #endregion

        public LiuSunTrackResult()
        {
        }

        #region element operation
        public void Add(PZPoint cp, PZPoint ep1, PZPoint ep2, SunScanline sl, PZDirection vd)
        {
            if (_count == 0)
            {
                _startCentrePoint.MemCopyFrom(cp);
                _startVesselDirection.MemCopyFrom(vd);
            }
            _count = _cpArray.Count;

            _endCentrePoint.MemCopyFrom(cp);
            _endVesselDirection.MemCopyFrom(vd);

            _cpArray.Add(cp);
            _vdArray.Add(vd);
            _ep1Array.Add(ep1);
            _ep2Array.Add(ep2);
            _rArray.Add(sl.Radius);
            _signalLevelArray.Add(sl.SignalLevel);
            _backgroundLevelArray.Add(sl.BackgroundLevel);           
        } // Add()

        /// <summary>
        /// another add function
        /// </summary>
        /// <param name="cp"></param>
        /// <param name="ep1"></param>
        /// <param name="ep2"></param>
        /// <param name="vd"></param>
        /// <param name="r"></param>
        /// <param name="mu"></param>
        /// <param name="B"></param>
        public void Add(PZPoint cp, PZPoint ep1, PZPoint ep2, PZDirection vd,
            double r, double signalLevel, double backgroundLevel)
        {
            if (_count == 0)
            {
                _startCentrePoint.MemCopyFrom(cp);
                _startVesselDirection.MemCopyFrom(vd);
            }
            _count = _cpArray.Count;

            _endCentrePoint.MemCopyFrom(cp);
            _endVesselDirection.MemCopyFrom(vd);

            _cpArray.Add(cp);
            _vdArray.Add(vd);
            _ep1Array.Add(ep1);
            _ep2Array.Add(ep2);
            _rArray.Add(r);
            _signalLevelArray.Add(signalLevel);
            _backgroundLevelArray.Add(backgroundLevel);
        } // Add()

        /// <summary>
        /// remove one element at "index"
        /// </summary>
        /// <param name="index"></param>
        public void RemoveAt(int index)
        {
            if (index < 0 || index >= _count)
                throw new ApplicationException("LiuSunTrackResult::Remove(), Index out of Range.");
            _cpArray.RemoveAt(index);
            _vdArray.RemoveAt(index);
            _ep1Array.RemoveAt(index);
            _ep2Array.RemoveAt(index);
            _rArray.RemoveAt(index);
            _signalLevelArray.RemoveAt(index);
            _backgroundLevelArray.RemoveAt(index);
            _count = _cpArray.Count;
            if (index == 0)
            {
                _startCentrePoint.MemCopyFrom(_cpArray[0]);
                _startVesselDirection.MemCopyFrom(_vdArray[0]);
            }
            if (index == _count - 1)
            {
                _endCentrePoint.MemCopyFrom(_cpArray[_count - 1]);
                _endVesselDirection.MemCopyFrom(_vdArray[_count - 1]);
            }
        } // RemoveAt()
        #endregion

        /// <summary>
        /// write to file
        /// </summary>
        /// <param name="filename"></param>
        public void Write(string filename)
        {
            FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
            StreamWriter w = new StreamWriter(fs);
            // start centre point and direction
            w.WriteLine(_startCentrePoint.ToString() + " " + _startVesselDirection.ToString());
            for (int i = 0; i < _cpArray.Count; i++)
            {
                w.Write(String.Format("{0, -5} ", (i + 1)));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_cpArray[i]).x));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_cpArray[i]).y));
                w.Write(String.Format("{0, -7:f} ", ((PZDirection)_vdArray[i]).x));
                w.Write(String.Format("{0, -7:f} ", ((PZDirection)_vdArray[i]).y));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_ep1Array[i]).x));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_ep1Array[i]).y));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_ep2Array[i]).x));
                w.Write(String.Format("{0, -7:f} ", ((PZPoint)_ep2Array[i]).y));
                w.Write(String.Format("{0, -7:f} ", (double)_rArray[i]));
                w.Write(String.Format("{0, -7:f} ", (double)_signalLevelArray[i]));
                w.WriteLine(String.Format("{0, -7:f}", (double)_backgroundLevelArray[i]));
            }
            w.Close();
            fs.Close();
        } // Write()

        /// <summary>
        /// read from file
        /// </summary>
        /// <param name="filename"></param>
        public void Read(string filename)
        {
            // clear ArrayList;
            _cpArray.Clear();
            _vdArray.Clear();
            _ep1Array.Clear();
            _ep2Array.Clear();
            _rArray.Clear();
            _signalLevelArray.Clear();
            _backgroundLevelArray.Clear();
            
            // read in a delimited file
            string[] fields;
            string[] firstLineDelimiter = new string[] { " ", ",", "(", ")" };
            string[] delimiter = new string[] { " " };
            string[] trackResult = new string[12];
            bool firstLine = true;
            using (Microsoft.VisualBasic.FileIO.TextFieldParser parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(filename))
            {
                parser.Delimiters = delimiter;
                while (!parser.EndOfData)
                {
                    if (firstLine)
                    // first line
                    {
                        parser.Delimiters = firstLineDelimiter;
                        fields = parser.ReadFields();
                        int j = 0;
                        for (int i = 0; i < fields.Length; i++)
                        {
                            if (fields[i] == "")
                                continue;
                            else
                            {
                                trackResult[j] = fields[i];
                                j++;
                            }
                        }
                        double cpx = Convert.ToDouble(trackResult[0]);
                        double cpy = Convert.ToDouble(trackResult[1]);
                        double vdx = Convert.ToDouble(trackResult[2]);
                        double vdy = Convert.ToDouble(trackResult[3]);
                        _startCentrePoint = new PZPoint(cpx, cpy);
                        _startVesselDirection = new PZDirection(vdx, vdy);
                        firstLine = false;
                    }
                    else
                    // rest of lines
                    {
                        parser.Delimiters = delimiter;
                        //Read in the fields for the current line
                        fields = parser.ReadFields();
                        int j = 0;
                        for (int i = 0; i < fields.Length; i++)
                        {
                            if (fields[i] == "")
                                continue;
                            else
                            {
                                trackResult[j] = fields[i];
                                j++;
                            }
                        }
                        // read to arrays
                        double cpx = Convert.ToDouble(trackResult[1]);
                        double cpy = Convert.ToDouble(trackResult[2]);
                        double vdx = Convert.ToDouble(trackResult[3]);
                        double vdy = Convert.ToDouble(trackResult[4]);
                        double ep1x = Convert.ToDouble(trackResult[5]);
                        double ep1y = Convert.ToDouble(trackResult[6]);
                        double ep2x = Convert.ToDouble(trackResult[7]);
                        double ep2y = Convert.ToDouble(trackResult[8]);
                        double inputr = Convert.ToDouble(trackResult[9]);
                        double inputSignalLevel = Convert.ToDouble(trackResult[10]);
                        double inputBackgroundLevel = Convert.ToDouble(trackResult[11]);
                        PZPoint cp = new PZPoint(cpx, cpy);
                        PZPoint ep1 = new PZPoint(ep1x, ep1y);
                        PZPoint ep2 = new PZPoint(ep2x, ep2y);
                        PZDirection vd = new PZDirection(vdx, vdy);
                        _cpArray.Add(cp);
                        _ep1Array.Add(ep1);
                        _ep2Array.Add(ep2);
                        _vdArray.Add(vd);
                        _rArray.Add(inputr);
                        _signalLevelArray.Add(inputSignalLevel);
                        _backgroundLevelArray.Add(inputBackgroundLevel);
                    }
                }
            }
            _count = _cpArray.Count;
        } // Read()
    }
}
